﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;

namespace JeanFish.Security
{
    /// <summary>
    /// An factory creating hash algorithm instance (HashHelper) of specific hash algorithm.
    /// </summary>
    public sealed class HashAlgorithmFactory:IHashAlgorithmFactory
    {    
        static HashAlgorithmFactory CreateFactory()
        {
            return new HashAlgorithmFactory();
        }

        static HashAlgorithmFactory(){
            if(Current==null)
                Current=CreateFactory();
        }
        /// <summary>
        /// Get current singleton of the factory.
        /// </summary>
        public static HashAlgorithmFactory Current{get;private set;}
        /// <summary>
        /// Get hash algorithm instance (HashHelper) by specifying the name of the algorithm.
        /// </summary>
        /// <param name="hashAlgorithm">Hash algorithm name</param>
        /// <returns>Hash algorithm instance (HashHelper)</returns>
        public HashHelper GetHashAlgorithm(string hashAlgorithm)
        {
            switch (hashAlgorithm)
            {
                case MD5:
                    return new HashHelper<MD5CryptoServiceProvider>();
                case SHA256:
                    return new HashHelper<SHA256CryptoServiceProvider>();
                case SHA512:
                    return new HashHelper<SHA512CryptoServiceProvider>();
                default:
                    throw new NotSupportedException("the algorithm is not supported.");
            }
        }

        private class HashHelper<THashAlgorithm> : JeanFish.Security.HashHelper
            where THashAlgorithm:HashAlgorithm
        {
            public HashAlgorithm hashProvider = null;

            public HashHelper()
            {
                hashProvider = Activator.CreateInstance<THashAlgorithm>();
            }
            public override string AlgorithmsType
            {
                get { return typeof(THashAlgorithm).ToString(); }
            }

            public override int HashSize
            {
                get { return hashProvider.HashSize; }
            }

            public override byte[] ComputeHash(byte[] data)
            {
                return hashProvider.ComputeHash(data);
            }
        }


        private const string MD5 = "MD5";

        private const string SHA256 = "SHA256";

        private const string SHA512 = "SHA512";

        /// <summary>
        /// Get the name of MD5 hash algorithm.
        /// </summary>
        string IHashAlgorithmFactory.MD5
        {
            get { return MD5; }
        }
        /// <summary>
        /// Get the name of SHA256 hash algorithm.
        /// </summary>
        string IHashAlgorithmFactory.SHA256
        {
            get { return SHA256; }
        }
        /// <summary>
        /// Get the name of SHA512 hash algorithm.
        /// </summary>
        string IHashAlgorithmFactory.SHA512
        {
            get { return SHA512; }
        }
    }
}
